﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;

namespace Needle.Framework
{
    /// <summary>
    /// A Container that implements IServiceProvider
    /// </summary>
    public class Container : System.ComponentModel.Container, IServiceProvider
    {
        #region constructors

        /// <summary>
        /// Default constructor
        /// </summary>
        public Container()
        { }

        #endregion

        #region properties

        private IServiceContainer _Services;
        /// <summary>
        /// The internal service container.
        /// </summary>
        private IServiceContainer Services
        {
            get
            {
                if (_Services == null)
                    _Services = CreateServiceContainer();
                return _Services;
            }
        }

        #endregion

        /// <summary>
        /// Overridden to create a custom ISite implementation.
        /// </summary>
        protected override ISite CreateSite(IComponent component, string name)
        {
            return new Site(component, this, name);
        }

        /// <summary>
        /// This method is called by the IServiceProvider.GetService(Type serviceType) implementation.
        /// </summary>
        protected override object GetService(Type serviceType)
        {
            object service = null;
            if (serviceType == typeof(IServiceProvider))
                return this;
            if (serviceType == typeof(IContainer))
                return this;
            if (Services != null)
                service = Services.GetService(serviceType);
            return service;
        }

        /// <summary>
        /// This method is called when a servicecontainer is needed,
        /// and provides a way to use a custom servicecontainer in a derived class.
        /// </summary>
        protected virtual IServiceContainer CreateServiceContainer()
        {
            return new ServiceContainer();
        }

        #region IServiceProvider Members

        object IServiceProvider.GetService(Type serviceType)
        {
            return GetService(serviceType);
        }

        #endregion

        #region Site implementation

        private class Site : ISite
        {

            internal Site(IComponent component, Container container, string name)
            {
                _component = component;
                _container = container;
                _name = name;
            }

            public object GetService(Type service)
            {
                if (service != typeof(ISite))
                {
                    return _container.GetService(service);
                }
                return this;
            }

            private IComponent _component;
            public IComponent Component
            {
                get { return _component; }
            }

            private Container _container;
            public IContainer Container
            {
                get { return _container; }
            }

            public bool DesignMode
            {
                get { return false; }
            }

            private string _name;
            public string Name
            {
                get { return _name; }
                set
                {
                    if (value == null || this._name == null || !value.Equals(this._name))
                    {
                        this._container.ValidateName(_component, value);
                        this._name = value;
                    }
                }
            }
        }

        #endregion

    }
}
